// =============================================================
// CMIMEServerCallback class
// ---------------------------------------
// Author : Woo-Hyun Kim
// Email : woorung@icu.ac.kr or woorung@nhncorp.com
// Date : Apr. 17, 2008
// =============================================================
#include "CMIMEServerCallback.h"
//---------------------------------------------------------------------------------------------
CMIMEServerCallback::CMIMEServerCallback() : CMIMECallback()
{
}

CMIMEServerCallback::~CMIMEServerCallback()
{
}

// the return is very important because it will be passed on to the read() and read_close() callbacks
// so the read_open()'s return value must be FILE * in that handle of read() and read_close() will be reused as a file descriptor
// If you don't want to use the streaming callback for this MIME attachement, your should return NULL
void *CMIMEServerCallback::read_open(struct soap *soap, void *handle, const char *id, const char *type, const char *description)
{ 
#ifdef DEBUG
	cerr << "[server callback]handle(remote file to read) = " << (char *)handle << endl;
	cerr << "[server callback]id(target file to save) = " << (char *)id << endl;
#endif

	FILE *fd = NULL;
	const char *file = (char *)handle;

	fd = (FILE *)fopen64((char *)file, "rb");
	if(!fd) {
		fclose(fd);

		string err_msg = "ERROR : cannot open file ";
		err_msg += soap->endpoint;
		err_msg += ":";
		err_msg += file;

		soap->error = soap_receiver_fault(soap, (char *)err_msg.c_str(), NULL);
		soap->errnum = errno;
		return NULL;
	}

	return (void*)fd;
}

size_t CMIMEServerCallback::read(struct soap *soap, void *handle, char *buf, size_t len)
{
	return fread(buf, 1, len, (FILE*)handle);
}

void CMIMEServerCallback::read_close(struct soap *soap, void *handle)
{
	fclose((FILE*)handle);
}

/**
 * Note : the 'unused_handle' is always NULL
 *        Return NULL without setting soap->error if we don't want to use the streaming callback for this DIME attachment
 */
void *CMIMEServerCallback::write_open(struct soap *soap, void *unused_handle, const char *id, const char *type, const char *description, enum soap_mime_encoding encoding)
{
	struct mime_server_handle *handle = (struct mime_server_handle *) soap_malloc(soap, sizeof(struct mime_server_handle));

	if(!handle) { 
		soap->error = SOAP_EOM;
    		return NULL;
	}

#ifdef UNIQUE_FILE_NAME
	char file[] = CUBE_ENV_UNIQUE_FILE_PREFIX;
#else

	char *file = (char *)id; // repository path + file name
	string tmp_file = file;
	string only_path = "";
	string::size_type pos = tmp_file.find_last_of("/"); // only path
	if(pos!=string::npos) only_path = tmp_file.substr(0, pos+1); 
	else only_path = ".";

	CFile file_util;
	if(file_util.exist_dir(only_path.c_str())==false) {
#ifdef AUTO_MAKE_DIR
		file_util.make_dir(only_path);
#else 
		string err_msg = "there is no " + only_path;

		soap->error = soap_sender_fault(soap, (char *)err_msg.c_str(), handle->key);
		soap->errnum = errno; /* get reason */

		return NULL;
#endif
	}
#endif


#ifdef UNIQUE_FILE_NAME
	int tmp_fd = mkstemp((char *)file);
	close(tmp_fd);
#endif

	handle->fd = (FILE *)fopen64(file, "w+b");
	handle->key = soap_strdup(soap, file);

	if(!handle->fd) { 
		string err_msg = "cannot save data to the file ";
		err_msg += handle->key;

		soap->error = soap_sender_fault(soap, (char *)err_msg.c_str(), handle->key);
		soap->errnum = errno; /* get reason */
		return NULL;
	}

	// change access mode
	umask(000);
	if(fchmod(fileno(handle->fd), S_IRUSR|S_IWUSR|S_IXUSR)<0) {
		string err_msg = "cannot change the access mode of the file ";
		err_msg += handle->key;

		soap->error = soap_receiver_fault(soap, (char *)err_msg.c_str(), handle->key);
		soap->errnum = errno;
		return NULL;
	}

	return (void*)handle;
}

int CMIMEServerCallback::write(struct soap *soap, void *handle, const char *buf, size_t len)
{
	FILE *fd = ((struct mime_server_handle*)handle)->fd;
	while(len) { 
		size_t nwritten = fwrite(buf, 1, len, fd);

    		if(!nwritten) { 
			soap->errnum = errno;
      			return SOAP_EOF;
    		}

		len -= nwritten;
		buf += nwritten;
  	}

	return SOAP_OK;
}

void CMIMEServerCallback::write_close(struct soap *soap, void *handle) 
{ 
	fclose(((struct mime_server_handle*)handle)->fd);
}
